# Generate api/BUILD based on API type database. This contains target for v2, v3
# and all API protos. This is not the ideal way to be generating docs, see
# https://github.com/envoyproxy/envoy/issues/10311#issuecomment-603518498.

import os
import re
import string
import sys

from tools.type_whisperer.api_type_db_pb2 import TypeDb

from google.protobuf import text_format

V2_REGEXES = list(
    map(re.compile, [
        r'envoy[\w\.]*\.(v1alpha\d?|v1)',
        r'envoy[\w\.]*\.(v2alpha\d?|v2)',
        r'envoy\.type\.matcher$',
        r'envoy\.type$',
        r'envoy\.config\.cluster\.redis',
        r'envoy\.config\.retry\.previous_priorities',
    ]))

V3_REGEX = re.compile(r'envoy[\w\.]*\.(v3alpha|v3)')

API_BUILD_FILE_TEMPLATE = string.Template(
    """# DO NOT EDIT. This file is generated by tools/proto_sync.py.

load("@rules_proto//proto:defs.bzl", "proto_library")

licenses(["notice"])  # Apache 2

proto_library(
    name = "v2_protos",
    visibility = ["//visibility:public"],
    deps = [
$v2_deps
    ],
)

proto_library(
    name = "v3_protos",
    visibility = ["//visibility:public"],
    deps = [
$v3_deps
    ],
)

proto_library(
    name = "all_protos",
    visibility = ["//visibility:public"],
    deps = [
        ":v2_protos",
        ":v3_protos",
    ],
)
""")


def LoadTypeDb(type_db_path):
  type_db = TypeDb()
  with open(type_db_path, 'r') as f:
    text_format.Merge(f.read(), type_db)
  return type_db


# Key sort function to achieve consistent results with buildifier.
def BuildOrderKey(key):
  return key.replace(':', '!')


# Remove any packages that are definitely non-root, e.g. annotations.
def FilterPkgs(pkgs):

  def AllowedPkg(pkg):
    return not pkg.startswith('envoy.annotations')

  return filter(AllowedPkg, pkgs)


def DepsFormat(pkgs):
  return '\n'.join('        "//%s:pkg",' % p.replace('.', '/')
                   for p in sorted(FilterPkgs(pkgs), key=BuildOrderKey))


def IsV2Package(pkg):
  for regex in V2_REGEXES:
    if regex.match(pkg):
      return True
  return False


def IsV3Package(pkg):
  return V3_REGEX.match(pkg) is not None


if __name__ == '__main__':
  type_db_path, output_path = sys.argv[1:]
  type_db = LoadTypeDb(type_db_path)
  # TODO(htuch): generalize to > 2 versions
  v2_packages = set([])
  v3_packages = set([])
  for desc in type_db.types.values():
    pkg = desc.qualified_package
    if IsV3Package(pkg):
      v3_packages.add(pkg)
      continue
    if IsV2Package(pkg):
      v2_packages.add(pkg)
      # Special case for v2 packages that are part of v3 (still active)
      if not desc.next_version_type_name:
        v3_packages.add(pkg)
  # Generate BUILD file.
  build_file_contents = API_BUILD_FILE_TEMPLATE.substitute(v2_deps=DepsFormat(v2_packages),
                                                           v3_deps=DepsFormat(v3_packages))
  with open(output_path, 'w') as f:
    f.write(build_file_contents)
